package org.example.cardgame.entity;

import org.example.cardgame.controller.PlayerWebSocket;
import org.example.cardgame.service.CardGroups;
import org.example.cardgame.service.PageHandle;
import org.example.cardgame.service.PlayerHandle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.websocket.Session;
import java.util.*;

/**
 * @Author juanita.ren
 * @Date 2024/11/11 22:10
 * @Version 1.0
 */

public class FlowManager {
    private static Logger logger = LoggerFactory.getLogger(FlowManager.class);
    private GameInfo gameInfo;
    private CardGroups cardGroups;
    private Map<Integer, PersonalInfo> personalInfoMap;
    private Thread flowThread = null;
    private WaitOperation waitOperation = null;
    private Map<String, Object> operateData = null;
    private static FlowManager instance = null;
    private static final long INTERVAL_TIME = 1000L;
    private boolean stopFlowFlag = false;

    public static FlowManager getInstance() {
        if (instance == null) {
            instance = new FlowManager();
        }

        return instance;
    }

    private void initData() {
        this.gameInfo = new GameInfo();
        this.cardGroups = new CardGroups();
        this.personalInfoMap = new HashMap();
        this.flowThread = null;
        this.waitOperation = null;
        this.operateData = null;
        this.stopFlowFlag = false;
    }

    public void restart() {
        this.stopFlowFlag = true;
    }

    private void onGameStart() throws FlowStopException {
        Map<Session, Map<String, Object>> sessionMap = PlayerWebSocket.getSessionMap();
        if (sessionMap.size() < 2) {
            throw new FlowStopException("玩家人数不足，无法开始游戏");
        } else {
            List<Session> sessionList = new ArrayList(sessionMap.keySet());
            List<Player> playerList = new ArrayList();

            for(int i = 0; i < sessionList.size(); ++i) {
                int role = Math.min(i, 3);
                Session session = (Session)sessionList.get(i);
                if (session.isOpen()) {
                    Player player = new Player();
                    player.setIndex(i);
                    player.setName(String.valueOf(((Map)sessionMap.get(session)).get("name")));
                    player.setPhoto(String.valueOf(((Map)sessionMap.get(session)).get("photo")));
                    player.setRole(role);
                    player.setSession(session);
                    playerList.add(player);
                }
            }

            Collections.shuffle(playerList);
            this.gameInfo.setPlayerList(playerList);
        }
    }

    private void onGameEnd() {
    }



    private List<Player> getSortPlayer() {
        int role0Index = 0;
        List<Player> playerList = this.gameInfo.getPlayerList();

        for(int i = 0; i < playerList.size(); ++i) {
            if (((Player)playerList.get(i)).getRole() == 0) {
                role0Index = i;
                break;
            }
        }

        List<Player> sortPlayerList = new ArrayList(playerList.subList(role0Index, playerList.size()));
        if (role0Index != 0) {
            sortPlayerList.addAll(playerList.subList(0, role0Index));
        }

        if (this.gameInfo.getRoundNum() != 1) {
            for(int i = 0; i < sortPlayerList.size(); ++i) {
                Player player = (Player)sortPlayerList.get(i);
                player.setRole(Math.min(i, 3));
            }
        }

        return sortPlayerList;
    }

    private void onRoundStart() {
        this.cardGroups.refreshGroup();
        this.gameInfo.setRoundNum(this.gameInfo.getRoundNum() + 1);
        this.gameInfo.setShowCard(this.cardGroups.drawCard(3));
        this.gameInfo.setScorePool(0);
        this.gameInfo.setCurrentScore(0);
        this.gameInfo.getPlayerList().forEach((playerx) -> {
            playerx.setIslost(0);
        });
        Iterator var1 = this.gameInfo.getPlayerList().iterator();

        while(var1.hasNext()) {
            Player player = (Player)var1.next();
            PlayerHandle.sendMessage(player, new Message("S_RoundStart", new HashMap()));
            PlayerHandle.sendMessage(player, new Message("S_GameRoundInfo", this.gameInfo));
            List<Card> cardList = this.cardGroups.drawCard(2);
            PersonalInfo personalInfo = new PersonalInfo();
            personalInfo.setPlayerIndex(player.getIndex());
            personalInfo.setRole(player.getRole());
            personalInfo.setCards(cardList);
            this.personalInfoMap.put(player.getIndex(), personalInfo);
            PlayerHandle.sendMessage(player, new Message("S_PlayerRoundInfo", personalInfo));
        }

        PageHandle.sendMessage(new Message("B_GameRoundInfo", this.gameInfo));
    }



    private Map<String, Object> waitOperationDoing(WaitOperation waitOperation) throws FlowStopException {
        this.waitOperation = waitOperation;
        this.onWaitStart();

        while(this.waitOperation == waitOperation) {
            if (this.stopFlowFlag) {
                throw new FlowStopException("游戏流程结束");
            }

            try {
                Thread.sleep(100L);
            } catch (InterruptedException var3) {
                InterruptedException e = var3;
                e.printStackTrace();
            }
        }

        this.waitOperation = null;
        this.onWaitEnd();
        return this.operateData;
    }

    public void receiveOperation(WaitOperation waitOperation, Map<String, Object> data) {
        if (this.waitOperation == waitOperation) {
            this.waitOperation = null;
            this.operateData = data;
        }

    }

    private void onWaitStart() {
    }

    private void onWaitEnd() {
    }

    private void waitIntervalTime() throws FlowStopException {
        if (this.stopFlowFlag) {
            throw new FlowStopException("游戏流程结束");
        } else {
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException var2) {
                InterruptedException e = var2;
                e.printStackTrace();
            }

        }
    }

    public static enum WaitOperation {
        PLAYER_OPERATE,
        ROUND_START;

        private WaitOperation() {
        }
    }
}
